\section{Descripción del problema}
El cálculo del número $\pi$ es un problema con muchas posibles
soluciones y que ha sido ampliamente abordado por numerosas
técnicas de programación y de métodos numéricos. 

El área bajo la curva $y=\frac{1}{1+x^2}$ entre $0$ y $1$ nos
proporciona un método para calcular $\pi$. Véase la figura~\ref{fig:calculopi}.

\begin{displaymath}
\int_{0}^{1}\frac{4}{1+x^2}dx=4\times arctan(x) |_0^1=4(\frac{\pi}{4} - 0) = \pi
\end{displaymath}

\begin{figure}[h!]
  \label{fig:calculopi}
  \centering
    \includegraphics[width=200pt]{images/calculopi.png}
  \caption{Calculo del numero $\pi$}
\end{figure}

Esta integral puede aproximarse por la suma:

\begin{displaymath}
\pi \simeq \sum_{i=0}^{N-1} \frac{4}{N \times (1 + (\frac{i+0.5}{N})^2 )}
\end{displaymath}

Supongamos entonces que tenemos un fragmento de código C como el que sigue:

\begin{verbatim}
   w = 1.0 / N;
   pi = 0.0;
   for (i = 0; i < N; i++) {
     local = (i + 0.5)*w;
     pi = pi + 4.0/(1.0 + local*local);
   }
\end{verbatim}

Un potencial usuario podría querer introducir mejoras
en este código o comparar ejecuciones de este mismo
programa en distintas máquinas.

Los parámetros a considerar en la ejecución del programa
son el número de intervalos $N$, el tiempo de ejecución
del algoritmo, y el valor de $\pi$ calculado.

\section{Instrumentación del programa}

Para que el módulo \texttt{Bench::Test} pueda realizar su labor
correctamente el usuario del programa debe instrumentarlo
de forma que todos los parámetros que le interesen sean
devueltos por el programa, ya sea volcando 
la salida en un fichero o mostrándola por pantalla
(\textit{Standard Output}).

El objeto \texttt{Bench::Test} lanza las ejecuciones y
obtiene la salida o la lee desde un fichero para
a continuación aplicar expresiones regulares que permitan
filtrar la información deseada. Por ello, a la hora
de instrumentar el programa debemos mostrar los
datos de forma que puedan ser fácilmente reconocidos
mediante una sencilla expresión regular.

En este caso, supongamos que se instrumenta el programa
enviando los resultados a la salida estándar. El código
quedaría como sigue:

\begin{verbatim}
   gettimeofday(&t1, NULL);

   w = 1.0 / N;
   pi = 0.0;
   for (i = 0; i < N; i++) {
     local = (i + 0.5)*w;
     pi = pi + 4.0/(1.0 + local*local);
   }
   gettimeofday(&t2, NULL);

   start = (double)(t1.tv_sec * 1.0e6) + (double)t1.tv_usec;
   end   = (double)(t2.tv_sec * 1.0e6) + (double)t2.tv_usec;
   diff  = (end - start) / 1.0e6;

   printf("Time: %f\n", diff);
   printf("Number of intervals: %d\n", N);
   printf("Calculated Pi: %1.20f\n", pi/N);
\end{verbatim}

\section{Parámetros de configuración}

Una vez instrumentado el programa cliente se han de
definir los parámetros que guíen las ejecuciones. Como ya
se ha explicado anteriormente en esta memoria,
para ello existen dos posibilidades:

\begin{itemize}
\item 
Escribir un script Perl que cree un objeto de la clase
Bench::Test con los parámetros adecuados (véase la
documentación del módulo \texttt{Bench::Test} en el
capítulo \ref{chapter:Bench-Test}).

\item 
Utilizar el script \texttt{maketest} proporcionado junto
con el modulo \texttt{Bench::Test} y definir los parámetros
mediante un fichero de configuración cuyo nombre, por defecto,
es \texttt{maketest.conf} (véase la documentación del
script \texttt{maketest} en el capítulo
\ref{chapter:maketest}).
\end{itemize}

La forma más sencilla para un usuario sin conocimientos
de Perl es escribir el fichero de configuración y hacer
uso del script proporcionado.

A continuación empezamos a escribir, paso a paso, el
fichero de configuración.

\section{Expresiones regulares}

La primera acción que realiza el objeto \texttt{Bench::Test}
después de cada ejecución es aplicar las expresiones
regulares sobre la salida generada por el programa
del usuario.

Estas expresiones definen los parámetros de estudio
en los que el usuario está interesado.

Para definirlas, se utiliza el array \texttt{@TABLE} y se
debe tener en cuenta el formato de salida del programa.

El resultado de una ejecución de nuestro programa
tendría un aspecto similar a éste:

\begin{verbatim}
   ~/Bench-Test/examples/pi$ ./pi 50000000
   Time: 0.644815
   Number of intervals: 50000000
   Calculated Pi: 3.14159265358952710656
\end{verbatim}

Para filtrar dicha salida el array \texttt{@TABLE}
debería tener la siguiente forma:

\begin{verbatim}
   @TABLE = (
      TIME => 'Time:\s+(.*?)\n',
      NOI  => 'Number of intervals: (.*?)\n',
      PI   => 'Calculated Pi: (.*?)\n',
   );
\end{verbatim}

Obsérvese que el array \texttt{@TABLE} está formado por
pares clave-valor cuya clave indica el nombre que el
usuario desea dar al campo objeto de estudio y cuyo
valor puede ser de dos tipos:

\begin{description}
\item[{\textbf{Cadena de caracteres:}}] \mbox{}

Contiene la expresión regular que permite filtrar la salida.
Debe estar parentizada en el lugar donde se encuentre el
campo que se desea filtrar.

\item[{\textbf{Referencia a rutina:}}] \mbox{}

En lugar de aplicar una expresión regular sobre la salida
se deja al usuario la responsabilidad del filtrado. La rutina
recibe como como parámetro la salida intacta del programa.
Este campo es muy útil a la hora de combinar varios resultados
en un solo campo.
\end{description}

\section{Parámetros de ejecución}

Una vez definidas las expresiones regulares que filtrarán
la salida del programa, es hora de indicar los parámetros
de ejecución.

Para ello se define el array \texttt{@TESTS} que, en este caso,
podría tener un aspecto similar a éste:

\begin{verbatim}
   @TESTS = (
      pi100000 =>    '100000',
      pi200000 =>    '200000',
      pi500000 =>    '500000',
      pi1000000 =>   '1000000',
   );
\end{verbatim}

Esta definición generaría cuatro ejecuciones de la forma:

\begin{verbatim}
   $ <ejecutable>  100000
   $ <ejecutable>  200000
   $ <ejecutable>  500000
   $ <ejecutable>  1000000
\end{verbatim}

Nótese que el array \texttt{@TESTS} está formado
por pares clave-valor. El valor indica el nombre
del test correspondiente. El nombre de este test estará
disponible al usuario como un campo llamado \texttt{NAME}
en la tabla final, como si hubiera sido definido en el
array \texttt{@TABLE}.

\section{Entornos de ejecución}

Todavía no se han definido en el fichero de configuración
los parámetros relacionados con el ejecutable y los entornos
de ejecución (máquinas remotas, conexiones). Para ello se utiliza
hash \texttt{\%EXPERIMENTS}.

El hash \texttt{\%EXPERIMENTS} está formado por pares clave-valor
cuyas claves son el nombre que el usuario quiere dar a
sus entornos de ejecución (por ejemplo, nombre de la máquina
donde se está ejecutando), y cuyo valor es una referencia
a un objeto de la clase \texttt{Bench::Test::Base}, \texttt{Bench::Test::Local}
o \texttt{Bench::Test::Remote}.

Para este ejemplo podríamos definir el hash \texttt{\%EXPERIMENTS} de
la siguiente forma:

\begin{verbatim}
   %EXPERIMENTS = (
      'FEB07'    => Bench::Test::Base->new (
                       WORKDIR   => './FEB07'
                 ),
      'LOCAL'    => Bench::Test::Local->new  (
                       WORKDIR   => '.',
                       EXECUTABLE => './pi',
                    ),
      'ORION'    => Bench::Test::Remote->new (
                       HOST       => 'user@host',
                       WORKDIR    => '/home/user/mm',
                       EXECUTABLE => 'pi',
                    ),
   );
\end{verbatim}

Esta definición contiene los tres posibles objetos: \texttt{Bench::Test::Base},
\texttt{Bench::Test::Local} y \texttt{Bench::Test::Remote}. La función de estos objetos
es definir los parámetros de ejecución en máquina local, remota o acceder
a resultados de ejecuciones anteriores.

\subsection{Objeto \texttt{Bench::Test::Base}}

El objeto \texttt{Bench::Test::Base} recibe como único parámetro
en el constructor el nombre del directorio en donde se encuentran
almacenados los ficheros con las salidas de las ejecuciones
anteriores con las que queremos comparar.

El nombre del archivo a leer consiste en nombre del \texttt{test} con la
extensión \texttt{.base} al final. El nombre del test se ha definido
anteriormente como clave de los pares almacenados en el array \texttt{@TEST}.

\subsection{Objeto \texttt{Bench::Test::Local}}

El objeto \texttt{Bench::Test::Local} se encarga de las ejecuciones en la 
máquina local. Su constructor recibe como parámetros el directorio
de trabajo donde se encuentra el ejecutable y el nombre del ejecutable.

\subsection{Objeto \texttt{Bench::Test::Remote}}

El objeto \texttt{Bench::Test::Remote} permite las ejecuciones en máquinas
remotas. Su constructor recibe como parámetros el nombre del host
(y usuario, si hiciera falta) donde se van a lanzar las ejecuciones.
También recibe el directorio de trabajo y el ejecutable en la
máquina remota.

Si el directorio de trabajo y el ejecutable no se encuentran en
la máquina remota, pueden definirse dos parámetros (\texttt{PREAMBLE} y
\texttt{POSTAMBLE}) que permiten al usuario subir archivos y ejecutar
comandos en dicha máquina. Se trata de dos referencias a rutina
que reciben como parámetro una referencia al objeto
\texttt{GRID::Machine} con el que se ha establecido la conexión con
la máquina remota.

El módulo \texttt{GRID::Machine} permite subir archivos y ejecutar comandos
en la máquina remota con la que ha establecido conexión a través
de SSH. Véase la do\-cu\-men\-ta\-ción de \texttt{GRID::Machine} para conocer
éstas y muchas otras funcionalidades.

\section{Validez de los tests}

Cada ejecución realizada genera un campo llamado \texttt{TEST} que
indica si el test es válido (\textit{ok}) o no válido (\textit{Fail}).
El usuario puede indicar la condición de validez de un test mediante la
rutina \texttt{Bench::Test::Entry::is\_ok}. Esta rutina recibe como
parámetro el objeto de la clase \texttt{Bench::Test::Entry} asociado al
test en cuestión. Este objeto tiene disponibles todos los valores
de los campos definidos por el usuario en el array \texttt{@TABLE} y
algunos otros métodos muy útiles. 

Un test se considera válido cuando la rutina \texttt{Bench::Test::Entry::is\_OK}
devuelve un valor verdadero. Si no fuera vital validar las ejecuciones, el usuario
podría escribir la rutina de forma que el resultado siempre fuese
válido:

\begin{verbatim}
   sub Bench::Test::Entry::is_OK {
      return 1;
   }
\end{verbatim}

En el cálculo del número $\pi$ sí es fundamental validar el resultado.
La rutina de validación de las ejecuciones podría tener el siguiente
aspecto:

\begin{verbatim}
   sub Bench::Test::Entry::is_OK {
      my $self = shift;
      my $pi = $self->get_field_value('PI');
      my $error = $pi - 3.14159265358979323846;

      return 1 if ( abs($error) < 0.001 );
      return 0;
   }
\end{verbatim}

En este ejemplo, se dan por válidos los tests que devuelven un valor
de $\pi$ con una error absoluto menor que $0.0001$.

\section{¿Qué campos mostrar?}

Es posible que en algún momento queramos ver u ocultar alguno
de los campos que hemos especificado en el array \texttt{@TABLE}. Para
ello se utiliza el array \texttt{@VISUAL}.

El array \texttt{@VISUAL} contiene una lista con los nombres de los
campos que queremos que aparezcan en la siguiente tanda de
ejecuciones. Por ejemplo:

\begin{verbatim}
   @VISUAL = ('TEST', 'NAME', 'NOI', 'TIME', 'PI');
\end{verbatim}

Otra forma más cómoda de escribir el array \texttt{@VISUAL} es
utilizar del operador \texttt{qw} de Perl:

\begin{verbatim}
   @VISUAL = qw(TEST NAME NOI TIME PI);
\end{verbatim}

En este caso se estaría indicando que se muestren
el número de intervalos utilizados para calcular el valor de $\pi$
(\texttt{NOI}), el tiempo de ejecución (\texttt{TIME}) y el valor de
$\pi$ obtenido con el programa (\texttt{PI}).
Los campos \texttt{TEST} y \texttt{NAME} son dos campos que se generan
automáticamente y que contienen el nombre del test y el resultado
(\textit{ok} o \textit{Fail}).

\section{Campos invariables}

Muchas veces ocurre que algunos campos son independientes del 
lugar donde se realizan las ejecuciones. En nuestro ejemplo,
el número de intervalos y el valor de $\pi$ son los mismos en la
máquina local que en la máquina remota puesto que el algoritmo
es el mismo. Para evitar que se muestren estos valores para ambas
máquinas se incluyen dichos campos en el array \texttt{@UNIQUE}:

\begin{verbatim}
   @UNIQUE = qw(NOI PI);
\end{verbatim}

\section{¿En qué máquinas ejecutar?}

Al igual que con los campos filtrados y el array \texttt{@VISUAL}, también
sería deseable poder evitar que se realicen ejecuciones en ciertas máquinas. En
el array \texttt{@SELECTED} se indican los nombres de los \texttt{EXPERIMENTS}
(máquinas) en los que se desea lanzar las ejecuciones. Por ejemplo:

\begin{verbatim}
   @SELECTED = qw(FEB07 LOCAL ORION);
\end{verbatim}

Al incluir todos los \texttt{EXPERIMENTS} se indica que se desea realizar 
las ejecuciones en todas las máquinas definidas anteriormente. Si no se quisiera
ejecutar en la máquina remota \texttt{ORION} , el array \texttt{@SELECTED} tendría la
siguiente forma:

\begin{verbatim}
   @SELECTED = qw(FEB07 LOCAL);
\end{verbatim}

\section{Formato de salida}

Por último, sólo queda definir el formato de salida con el 
array \texttt{@OUTPUTFORMAT}. A continuación un ejemplo:

\begin{verbatim}
   @OUTPUTFORMAT = (
      'text'  => '',
      'html'   => 'output.html',
   );
\end{verbatim}

Se trata de un hash cuyas claves indican el formato en el
que se quiere la salida y cuyo valor especifica el fichero
a donde se debe enviar la salida con dicho formato. Si se deja
el valor en blanco la salida se muestra por pantalla.

Los formatos disponibles son \texttt{text} (texto plano), \texttt{xml},
\texttt{html} y \texttt{latex}. Además es posible que el usuario provea
un nuevo formato mediante la clave \texttt{file:fichero.tt} donde
\texttt{fichero.tt} es el nombre del fichero en el que el usuario
ha escrito su plantilla con Template Toolkit. 

Para poder formatear la salida se debe esperar hasta que
se realice la última ejecución. Sin embargo,
se muestran por pantalla línea a línea los resultados de
cada ejecución formateados con simples tabuladores.

\newpage

\section{Fichero de configuración}

El fichero de configuración quedaría como sigue:

\begin{small}
\begin{verbatim}
   @TABLE = (
      TIME => {  REGEXP => 'Time:\s+(.*?)\n' },
      NOI  => {  REGEXP => 'Number of intervals: (.*?)\n' },
      PI   => {  REGEXP => 'Calculated Pi: (.*?)\n' },
   );
\end{verbatim}
\begin{verbatim}
   @TESTS = (
      pi100000 =>    '100000',
      pi200000 =>    '200000',
      pi500000 =>    '500000',
      pi1000000 =>   '1000000',
   );
\end{verbatim}
\begin{verbatim}
   %EXPERIMENTS = (
      'FEB07'     => Bench::Test::Base->new (
                       WORKDIR   => './FEB07'
                 ),
      'LOCAL'    => Bench::Test::Local->new  (
                       WORKDIR   => '.',
                       EXECUTABLE => './pi',
                    ),
      'ORION'    => Bench::Test::Remote->new (
                       HOST       => 'user@host',
                       WORKDIR    => '/home/user/pi',
                       EXECUTABLE => 'pi',
                    ),
   );
\end{verbatim}
\begin{verbatim}
   sub Bench::Test::Entry::is_OK {
      my $self = shift;
      my $pi = $self->get_field_value('PI');

      if ( ($pi - 3.141592) < 0.0001 ) {
         return 1;
      }
      return 0;
   }
\end{verbatim}
\begin{verbatim}
   @VISUAL   = qw(TEST NAME NOI TIME PI);
   @UNIQUE   = qw(NOI PI);
   @SELECTED = qw(FEB07 LOCAL ORION);
\end{verbatim}
\begin{verbatim}
   @OUTPUTFORMAT = (
      'text'  => '',
      'html'   => 'output.html',
   );
\end{verbatim}
\end{small}

\section{Resultado}

Una ejecución del script \texttt{maketest} con el fichero de configuración
anteriormente descrito daría como resultado algo como:

\begin{small}
\begin{verbatim}
   $ ./maketest 
   TEST    NAME    NOI  TIME(FEB07)   TIME(LOCAL)  PI(FEB07)   PI(LOCAL)
   ok      pi100000     100000  0.004671    0.004674   3.141593   3.141593
   ok      pi200000     200000  0.009338    0.010051   3.141593   3.141593
   ok      pi500000     500000  0.023357    0.019483   3.141593   3.141593
   ok      pi1000000    1000000 0.042296    0.022002   3.141593   3.141593
   TEST  NAME       NOI      TIME(FEB07)  TIME(LOCAL)  PI(FEB07)  PI(LOCAL)  
   ok    pi100000   100000   0.004671     0.004674     3.141593   3.141593   
   ok    pi200000   200000   0.009338     0.010051     3.141593   3.141593   
   ok    pi500000   500000   0.023357     0.019483     3.141593   3.141593   
   ok    pi1000000  1000000  0.042296     0.022002     3.141593   3.141593   
\end{verbatim}
\end{small}

La primera tabla se va generando ejecución a ejecución
mientras que la segunda se muestra al final de todas las ejecuciones
para ser formateada correctamente.

\begin{figure}
  \centering
    \includegraphics[width=\textwidth]{images/outputhtml.png}
  \caption{Salida en formato HTML vista en un navegador}
  \label{fig:outputhtml}
\end{figure}

Además, como se especificó en el array \texttt{@OUTPUTFORMAT} se crea un archivo
\texttt{output.html} cuyo aspecto puede verse en la figura~\ref{fig:outputhtml}.


